{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DcziiQNCZi7z"
      },
      "source": [
        "# Customer Service Discord Bot Using Cohere model with Agentic RAG\n",
        "\n",
        "In this cookbook, we are going to be implementing a Discord bot that provides customer service assistance for the Cohere AI platform via its comprehensive\n",
        "documentation sources and listings.\n",
        "\n",
        "<div class=\"align-center\">\n",
        "  <a href=\"https://www.camel-ai.org/\"><img src=\"https://i.postimg.cc/KzQ5rfBC/button.png\"width=\"150\"></a>\n",
        "  <a href=\"https://discord.camel-ai.org\"><img src=\"https://i.postimg.cc/L4wPdG9N/join-2.png\"  width=\"150\"></a></a>\n",
        "  \n",
        "⭐ <i>Star us on [*Github*](https://github.com/camel-ai/camel), join our [*Discord*](https://discord.camel-ai.org) or follow our [*X*](https://x.com/camelaiorg)\n",
        "</div>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "auMWFWdmZi71"
      },
      "source": [
        "## Installation and Setup  \n",
        "Setting up environment, by installing the CAMEL package with all its dependencies"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "eYIPPfHAZi71"
      },
      "outputs": [],
      "source": [
        "!pip install \"camel-ai[all]==0.2.16\"\n",
        "!pip install starlette\n",
        "!pip install nest_asyncio"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EWVuxF3hZi72"
      },
      "source": [
        "Next, proceed with setting up API keys for Firecrawl and the model (Cohere)\n",
        "\n",
        "If you don't have a FireCrawl API key, you can obtain one by following these steps:\n",
        "\n",
        "1. Visit the FireCrawl API Key page https://www.firecrawl.dev/app/api-keys\n",
        "\n",
        "2. Log in or sign up for a FireCrawl account.\n",
        "\n",
        "3. Navigate to the 'API Keys' section.\n",
        "\n",
        "4. Click on 'Create API Key' button to generate a new API key.\n",
        "\n",
        "For more details, you can also check the Firecrawl documentation: https://docs.firecrawl.dev/api-reference/introduction"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "seKoFg-UZi72"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "from getpass import getpass\n",
        "\n",
        "firecrawl_api_key = getpass(\"Enter your API key: \")\n",
        "os.environ[\"FIRECRAWL_API_KEY\"] = firecrawl_api_key"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "m6_Dy33sZi72"
      },
      "source": [
        "If you don't have a Cohere API key, you can obtain one by following these steps:\n",
        "\n",
        "1. Visit the Cohere dashboard (https://dashboard.cohere.com/api-keys) and follow the on-screen instructions related to account signup/login.\n",
        "\n",
        "2. In the left pane dashboard, search for the term \"API Keys\".\n",
        "\n",
        "3. On the API Key management page, click on the \"Create Trial Key\" button under the Trial keys section to generate a new trial key without any subscription.\n",
        "\n",
        "For more details, you can also check Cohere's documentation: https://docs.cohere.com/cohere-documentation"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "w8U-W14MZi72"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "from getpass import getpass\n",
        "\n",
        "cohere_api_key = getpass(\"Enter your API key: \")\n",
        "os.environ[\"COHERE_API_KEY\"] = cohere_api_key"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mQU1cdzJZi72"
      },
      "source": [
        "## Knowledge Crawling and Storage\n",
        "\n",
        "Use Firecrawl to crawl a website and store the content in a markdown file:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jB4bwYJ5Zi73"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "from camel.loaders import Firecrawl\n",
        "\n",
        "os.makedirs('local_data', exist_ok=True)\n",
        "\n",
        "firecrawl = Firecrawl()\n",
        "\n",
        "knowledge = firecrawl.crawl(\n",
        "    url=\"https://docs.cohere.com/docs/the-cohere-platform\"\n",
        ")[\"data\"][0][\"markdown\"]\n",
        "\n",
        "with open('local_data/cohere_platform.md', 'w') as file:\n",
        "     file.write(knowledge)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "f4RnSKfoZi73"
      },
      "source": [
        "## Basic Agent Setup\n",
        "\n",
        "Command R is a large language model optimized for conversational interaction and long context tasks. It targets the “scalable” category of models that balance high performance with strong accuracy, enabling companies to move beyond proof of concept and into production.\n",
        "\n",
        "Use Command R  model:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "90Q9mtrPZi74"
      },
      "outputs": [],
      "source": [
        "from camel.configs import CohereConfig\n",
        "from camel.models import ModelFactory\n",
        "from camel.types import ModelPlatformType, ModelType\n",
        "\n",
        "cohere_model = ModelFactory.create(\n",
        "    model_platform=ModelPlatformType.COHERE,\n",
        "    model_type=ModelType.COHERE_COMMAND_R,\n",
        "    model_config_dict=CohereConfig(temperature=0.0).as_dict(),\n",
        ")\n",
        "\n",
        "\n",
        "# Use Cohere model\n",
        "model = cohere_model\n",
        "\n",
        "# Setting up a ChatAgent with a system prompt\n",
        "from camel.agents import ChatAgent\n",
        "from camel.messages import BaseMessage\n",
        "\n",
        "agent = ChatAgent(\n",
        "    system_message=\"You're a helpful assistant\",\n",
        "    message_window_size=10,\n",
        "    model=model\n",
        ")\n",
        "\n",
        "knowledge_message = BaseMessage.make_user_message(\n",
        "    role_name=\"User\", content=f\"Based on the following knowledge: {knowledge}\"\n",
        ")\n",
        "agent.update_memory(knowledge_message, \"user\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YG68UVGbZi74"
      },
      "source": [
        "## Basic Chatbot Setup"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "xqE8O5JSZi74",
        "outputId": "bd69ac6e-9082-4883-f155-c590b3932688"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Start chatting! Type 'exit' to end the conversation.\n",
            "Assistant: Here are some of Cohere's latest models:\n",
            "\n",
            " - Command A\n",
            " - Command R7B\n",
            " - Command R+\n",
            " - Command R\n",
            " - Rerank\n",
            " - Embed\n",
            "\n",
            "You can find a full list of Cohere's models and more detailed information about them on the official Cohere website and documentation. The models I mentioned above are from the Command family of models and are primarily focused on text generation for applications like conversational agents, summarization, and copywriting.\n",
            "\n",
            "Additionally, Cohere also offers models for specific use cases, such as:\n",
            "\n",
            " - Retrieval Augmented Generation (RAG): Enables the model to access external data sources, improving the accuracy and factuality of its responses.\n",
            " - Fine-Tuning: Custom models can be created by uploading a dataset, and Cohere trains and deploys the model for the user. This can be done with generative models, multi-label classification models, rerank models, and chat models.\n",
            " - Semantic Search: Embeddings-based search goes beyond keywords and considers the context and user intent to provide more meaningful results.\n",
            "\n",
            "Cohere also continuously works on improving its models and platform to make them more accessible and powerful. Remember to check the Cohere website for the most up-to-date information and any new additions!\n",
            "Ending conversation.\n"
          ]
        }
      ],
      "source": [
        "print(\"Start chatting! Type 'exit' to end the conversation.\")\n",
        "while True:\n",
        "    user_input = input(\"User: \")\n",
        "\n",
        "    if user_input.lower() == \"exit\":\n",
        "        print(\"Ending conversation.\")\n",
        "        break\n",
        "\n",
        "    assistant_response = agent.step(user_input)\n",
        "    print(f\"Assistant: {assistant_response.msgs[0].content}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9XygYToUZi75"
      },
      "source": [
        "## Basic Discord Bot Integration\n",
        "\n",
        "To build a discord bot, a discord bot token is necessary.\n",
        "\n",
        "If you don't have a bot token, you can obtain one by following these steps:\n",
        "\n",
        "1. Go to the Discord Developer Portal:https://discord.com/developers/applications\n",
        "\n",
        "2. Log in with your Discord account, or create an account if you don't have one\n",
        "\n",
        "3. Click on 'New Application' to create a new bot.\n",
        "\n",
        "4. Give your application a name and click 'Create'.\n",
        "\n",
        "5. Navigate to the 'Bot' tab on the left sidebar and click 'Add Bot'.\n",
        "\n",
        "6. Once the bot is created, you will find a 'Token' section. Click 'Reset Token' to generate a new token.\n",
        "\n",
        "7. Copy the generated token securely.\n",
        "\n",
        "To invite the bot:\n",
        "\n",
        "1. Navigate to the 'OAuth2' tab, then to 'URL Generator'.\n",
        "\n",
        "2. Under 'Scopes', select 'bot'.\n",
        "\n",
        "3. Under 'Bot Permissions', select the permissions your bot will need (e.g., 'Send Messages', 'Read Messages' for our bot use)\n",
        "\n",
        "4. Copy the generated URL and paste it into your browser to invite the bot to your server.\n",
        "\n",
        "To grant the bot permissions:\n",
        "\n",
        "1. Navigate to the 'Bot' tab\n",
        "\n",
        "2. Under 'Privileged Gateway Intents', check 'Server Members Intent' and 'Message Content Intent'.\n",
        "\n",
        "For more details, you can also check the official Discord bot documentation: https://discord.com/developers/docs/intro\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2LahZ6ZIZi75"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "from getpass import getpass\n",
        "\n",
        "discord_bot_token = getpass('Enter your Discord bot token: ')\n",
        "os.environ[\"DISCORD_BOT_TOKEN\"] = discord_bot_token"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GLRIt2maZi75"
      },
      "source": [
        "This code cell sets up a simple Discord bot using the DiscordApp class from the camel.bots library. The bot listens for messages in any channel it has access to and provides a response based on the input message."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "trbwrYZ4Zi75",
        "outputId": "f2c9c1ba-8e6f-45f5-c5a8-43344c379425"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "[2025-04-15 02:51:34] [INFO    ] discord.client: logging in using static token\n",
            "[2025-04-15 02:51:34] [INFO    ] discord.client: logging in using static token\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2025-04-15 02:51:34,062 - discord.client - INFO - logging in using static token\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "[2025-04-15 02:51:36] [INFO    ] discord.gateway: Shard ID None has connected to Gateway (Session ID: 24062ffe37fc004bc4cdf22b7191e936).\n",
            "[2025-04-15 02:51:36] [INFO    ] discord.gateway: Shard ID None has connected to Gateway (Session ID: 24062ffe37fc004bc4cdf22b7191e936).\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2025-04-15 02:51:36,780 - discord.gateway - INFO - Shard ID None has connected to Gateway (Session ID: 24062ffe37fc004bc4cdf22b7191e936).\n"
          ]
        }
      ],
      "source": [
        "from camel.bots import DiscordApp\n",
        "import nest_asyncio\n",
        "import discord\n",
        "\n",
        "nest_asyncio.apply()\n",
        "discord_bot = DiscordApp(token=discord_bot_token)\n",
        "\n",
        "@discord_bot.client.event\n",
        "async def on_message(message: discord.Message):\n",
        "    if message.author == discord_bot.client.user:\n",
        "        return\n",
        "\n",
        "    if message.type != discord.MessageType.default:\n",
        "        return\n",
        "\n",
        "    if message.author.bot:\n",
        "        return\n",
        "    user_input = message.content\n",
        "\n",
        "    agent.reset()\n",
        "    agent.update_memory(knowledge_message, \"user\")\n",
        "    assistant_response = agent.step(user_input)\n",
        "\n",
        "    response_content = assistant_response.msgs[0].content\n",
        "\n",
        "    if len(response_content) > 2000: # discord message length limit\n",
        "        for chunk in [response_content[i:i+2000] for i in range(0, len(response_content), 2000)]:\n",
        "            await message.channel.send(chunk)\n",
        "    else:\n",
        "        await message.channel.send(response_content)\n",
        "\n",
        "discord_bot.run()"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "![250415_02h58m41s_screenshot.png]()"
      ],
      "metadata": {
        "id": "vm7KtY-mZpvm"
      }
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v4QyHGzNZi76"
      },
      "source": [
        "## Integrating Qdrant for Large Files to build a more powerful Discord bot\n",
        "\n",
        "Qdrant is a vector similarity search engine and vector database. It is designed to perform fast and efficient similarity searches on large datasets of vectors. This enables the chatbot to access and utilize external information to provide more comprehensive and accurate responses. By storing knowledge as vectors, Qdrant enables efficient semantic search, allowing the chatbot to find relevant information based on the meaning of the user's query.\n",
        "\n",
        "Set up an embedding model and retriever for Qdrant:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "mdQD6vVCZi76",
        "outputId": "8dad310f-64ce-4a4b-d3d9-f687eb576ef3"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "/home/hurtbadly/miniforge3/envs/camel/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
            "  from .autonotebook import tqdm as notebook_tqdm\n"
          ]
        }
      ],
      "source": [
        "from camel.embeddings import SentenceTransformerEncoder\n",
        "\n",
        "sentence_encoder = SentenceTransformerEncoder(model_name='intfloat/e5-large-v2')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "M_Q1Yc82Zi77"
      },
      "source": [
        "Set up the AutoRetriever for automatically retrieving relevant information from a storage system."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "JpqVtOpCZi77"
      },
      "outputs": [],
      "source": [
        "from camel.retrievers import AutoRetriever\n",
        "from camel.types import StorageType\n",
        "\n",
        "assistant_sys_msg = \"\"\"You are a helpful assistant to answer question,\n",
        "         I will give you the Original Query and Retrieved Context,\n",
        "        answer the Original Query based on the Retrieved Context,\n",
        "        if you can't answer the question just say I don't know.\"\"\"\n",
        "auto_retriever = AutoRetriever(\n",
        "              vector_storage_local_path=\"local_data2/\",\n",
        "              storage_type=StorageType.QDRANT,\n",
        "              embedding_model=sentence_encoder\n",
        "            )\n",
        "qdrant_agent = ChatAgent(system_message=assistant_sys_msg, model=model)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Tqt2sIiAZi77"
      },
      "source": [
        "Use Auto RAG to retrieve first and then answer the user's query using CAMEL `ChatAgent` based on the retrieved info:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "MlKHdGg2Zi77"
      },
      "outputs": [],
      "source": [
        "from camel.bots import DiscordApp\n",
        "import nest_asyncio\n",
        "import discord\n",
        "\n",
        "nest_asyncio.apply()\n",
        "discord_q_bot = DiscordApp(token=discord_bot_token)\n",
        "\n",
        "@discord_q_bot.client.event # triggers when a message is sent in the channel\n",
        "async def on_message(message: discord.Message):\n",
        "    if message.author == discord_q_bot.client.user:\n",
        "        return\n",
        "\n",
        "    if message.type != discord.MessageType.default:\n",
        "        return\n",
        "\n",
        "    if message.author.bot:\n",
        "        return\n",
        "    user_input = message.content\n",
        "\n",
        "    retrieved_info = auto_retriever.run_vector_retriever(\n",
        "        query=user_input,\n",
        "        contents=[\n",
        "            \"local_data/cohere_platform.md\",\n",
        "        ],\n",
        "        top_k=3,\n",
        "        return_detailed_info=False,\n",
        "        similarity_threshold=0.5\n",
        "    )\n",
        "\n",
        "    user_msg = str(retrieved_info)\n",
        "    assistant_response = qdrant_agent.step(user_msg)\n",
        "    response_content = assistant_response.msgs[0].content\n",
        "\n",
        "    if len(response_content) > 2000: # discord message length limit\n",
        "        for chunk in [response_content[i:i+2000] for i in range(0, len(response_content), 2000)]:\n",
        "            await message.channel.send(chunk)\n",
        "    else:\n",
        "        await message.channel.send(response_content)\n",
        "\n",
        "discord_q_bot.run()"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "![250415_02h58m26s_screenshot.png]()"
      ],
      "metadata": {
        "id": "KUiMDynVamwd"
      }
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8B1xvRftZi78"
      },
      "source": [
        "That's everything: Got questions about 🐫 CAMEL-AI? Join us on [Discord](https://discord.camel-ai.org)! Whether you want to share feedback, explore the latest in multi-agent systems, get support, or connect with others on exciting projects, we’d love to have you in the community! 🤝\n",
        "\n",
        "Check out some of our other work:\n",
        "\n",
        "1. 🐫 Creating Your First CAMEL Agent [free Colab](https://docs.camel-ai.org/cookbooks/create_your_first_agent.html)\n",
        "\n",
        "2.  Graph RAG Cookbook [free Colab](https://colab.research.google.com/drive/1uZKQSuu0qW6ukkuSv9TukLB9bVaS1H0U?usp=sharing)\n",
        "\n",
        "3. 🧑‍⚖️ Create A Hackathon Judge Committee with Workforce [free Colab](https://colab.research.google.com/drive/18ajYUMfwDx3WyrjHow3EvUMpKQDcrLtr?usp=sharing)\n",
        "\n",
        "4. 🔥 3 ways to ingest data from websites with Firecrawl & CAMEL [free Colab](https://colab.research.google.com/drive/1lOmM3VmgR1hLwDKdeLGFve_75RFW0R9I?usp=sharing)\n",
        "\n",
        "5. 🦥 Agentic SFT Data Generation with CAMEL and Mistral Models, Fine-Tuned with Unsloth [free Colab](https://colab.research.google.com/drive/1lYgArBw7ARVPSpdwgKLYnp_NEXiNDOd-?usp=sharingg)\n",
        "\n",
        "Thanks from everyone at 🐫 CAMEL-AI"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZPtpf-K2Zi78"
      },
      "source": [
        "⭐ **Star the Repo**\n",
        "\n",
        "If you find CAMEL useful or interesting, please consider giving it a star on our [CAMEL GitHub Repo](https://github.com/camel-ai/camel)! Your stars help others find this project and motivate us to continue improving it."
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "camel",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.9"
    },
    "colab": {
      "provenance": []
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
